﻿using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Web;
using CSVideoUploader.Http;
using CSVideoUploader.IO;
using System.Threading;
using System.Text.RegularExpressions;
using System.IO;
using CSVideoUploader.Util;

namespace CSVideoUploader.Client.Xina
{
    /// <summary>
    /// 渣浪客户端类基类
    /// 只实现了登录的方法，上传方法需要子类实现
    /// </summary>
    abstract class XinaClient
    {

        #region 接口地址定义
        /// <summary>预登录地址</summary>
        const string PRELOGIN_URL = "http://login.sina.com.cn/sso/prelogin.php";
        /// <summary>登录地址</summary>
        const string LOGIN_URL = "http://login.sina.com.cn/sso/login.php?client=sinaSSOManager.js(v1.2.3)";
        /// <summary>可以拿到hach的地址</summary>
        const string HACH_URL = "http://vupload.you.video.sina.com.cn/u.php?m=1";
        /// <summary>提交视频文件的地址</summary>
        const string UPLOAD_URL = "http://vupload.you.video.sina.com.cn/cgi-bin/post_utf8_vip.cgi?";
        /// <summary>监视上传进度的地址</summary>
        const string HANDLE_URL = "http://vupload.you.video.sina.com.cn/cgi-bin/handle_utf8.cgi";
        /// <summary>不知道用途但是有必要访问的URL之1</summary>
        const string UNKNOWN1_URL = "http://control.video.sina.com.cn/useradmin/topicsset/getUserSpecial.php?page=1&pagesize=6&callback=&random=";
        /// <summary>提交视频信息的地址</summary>
        const string POST_INFO_URL = "http://vupload.you.video.sina.com.cn/upload_com_utf8.php";
        /// <summary>不知道用途但是有必要访问的URL之2</summary>
        const string UNKNOWN2_URL = "http://you.video.sina.com.cn/upload_succ.php?topicid=&m=1";
        #endregion

        #region 变量定义
        /// <summary>渣浪用户名</summary>
        private string username;
        /// <summary>标记是否登录成功</summary>
        private bool bIsLogin = false;
        /// <summary>Http客户端</summary>
        protected HttpClient client = null;
        #endregion

        public XinaClient(string username)
        {
            this.username = username;

            // 初始化HttpClient
            // 结果渣浪还是只支持GB2312嘛，什么UTF-8都是骗人的
            client = new HttpClient("GB2312");
        }

        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="password">密码</param>
        /// <param name="door">验证码</param>
        /// <returns></returns>
        public bool Login(string password, string door = null)
        {
            try
            {
                Logger.Info("开始登陆帐户 " + username);

                // 登录预处理，请求公钥等信息
                PreLoginResult pr = DoPreLogin();
                if (pr.retcode != 0)
                    throw new Exception("预登录处理失败！");
                // 登录
                LoginResult lr = DoLogin(pr, password, null);
                if (lr.retcode != 0)
                    throw new Exception("登录失败，服务其返回错误码：" + lr.retcode);

                // 登录后续处理
                DoAfterLogin(lr);

                bIsLogin = true;

                Logger.Info("登陆成功！");
            }
            catch (Exception e)
            {
                bIsLogin = false;
                Console.WriteLine(e.StackTrace);
            }

            return bIsLogin;
        }

        /// <summary>
        /// 执行预登录动作
        /// 获取登录所需的相关参数
        /// </summary>
        /// <returns></returns>
        private PreLoginResult DoPreLogin()
        {
            // 构建URL
            StringBuilder sb = new StringBuilder();
            sb.Append(PRELOGIN_URL)
                .Append("?entry=vblog")
                .Append("&callback=sinaSSOManager.preloginCallBack")
                .Append("&su=").Append(HttpUtility.UrlEncode(XinaUtility.EncodeUsername(username)))
                .Append("&rsakt=mod");
            // 执行请求
            string body = client.Get(sb.ToString());
            // 解析结果
            int pos = body.IndexOf('{');
            body = body.Substring(pos, body.Length - pos - 1);
            DataContractJsonSerializer jsonSer = new DataContractJsonSerializer(typeof(PreLoginResult));
            PreLoginResult result = (PreLoginResult)jsonSer.ReadObject(new StringStream(body));

            return result;
        }

        /// <summary>
        /// 执行登录动作
        /// </summary>
        /// <param name="pr"></param>
        /// <param name="door"></param>
        /// <returns></returns>
        private LoginResult DoLogin(PreLoginResult pr, string password, string door)
        {
            Dictionary<string, string> datas = new Dictionary<string, string>(15);
            datas.Add("entry", "vblog");
            datas.Add("service", "vblog");
            datas.Add("encoding", "UTF-8");
            datas.Add("client", "sinaSSOManager.js(v1.2.3)");
            datas.Add("callback", "parent.sinaSSOManager.lb");
            datas.Add("returntype", "IFRAME");
            datas.Add("savestate", "30");
            datas.Add("useticket", "0");
            datas.Add("setdomain", "1");
            datas.Add("gateway", "1");
            datas.Add("vsnf", "1");
            datas.Add("pwencode", "rsa2");
            datas.Add("rsakv", pr.rsakv);
            datas.Add("su", XinaUtility.EncodeUsername(username));
            datas.Add("sp", XinaUtility.EncodePassword(password, pr.servertime, pr.nonce, pr.pubkey));
            if (door != null)
                datas.Add("door", door);

            string body = client.Post(LOGIN_URL, datas);
            int pos = body.IndexOf("setCrossDomainUrlList(");
            if (pos < 0)
                throw new Exception("登录失败！返回结果不正确");

            // 拆分出json部分
            body = body.Substring(pos + 22, body.IndexOf("})") - pos - 21);
            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(LoginResult));
            LoginResult lr = (LoginResult)ser.ReadObject(new StringStream(body));

            return lr;
        }

        /// <summary>
        /// 登录后续处理
        /// </summary>
        private void DoAfterLogin(LoginResult lr)
        {
            try
            {
                // 依次访问后续地址
                foreach (string u in lr.arrURL)
                {
                    client.Get(u);
                }
            }
            catch (Exception)
            {
            }
        }

        /// <summary>
        /// 是否已登录
        /// </summary>
        /// <returns></returns>
        public bool IsLogin()
        {
            return bIsLogin;
        }

        /// <summary>
        /// 上传视频
        /// </summary>
        /// <param name="task">任务信息</param>
        /// <param name="listener">进度监听器</param>
        public abstract void Upload(XinaUploadTask task, IUploadProgressListener listener);

    }

    #region 数据结构部分
    [DataContract]
    struct PreLoginResult
    {
        [DataMember]
        public int retcode { get; set; }
        [DataMember]
        public long servertime { get; set; }
        [DataMember]
        public string pcid { get; set; }
        [DataMember]
        public string nonce { get; set; }
        [DataMember]
        public string pubkey { get; set; }
        [DataMember]
        public string rsakv { get; set; }
    }

    [DataContract]
    struct LoginResult
    {
        [DataMember]
        public int retcode { get; set; }
        [DataMember]
        public List<string> arrURL { get; set; }
    }
    #endregion
}
